#pragma comment( lib, "glew32.lib" )
//#pragma comment( lib, "glew32s.lib" )
#pragma comment( lib, "glfwdll.lib" )
#pragma comment( lib, "opengl32.lib" ) // not needed?


#include <game.h>

#include <cmath>
#include <vector>
#include <algorithm> // min max

// GLminimal
#include "GLMinimal.h"

// GLEW & GLFW
#include <gl\glew.h>
#include <gl\glfw.h>

// Misrender
#include "graphicsmanager.h"
#include "texture.h"
#include "PastyCam.h"
// Game
#include "GameObject.h"
#include "player.h"
#include "enemy.h"

#ifndef M_PI
#define M_PI 3.14159
#endif

Game::Game()
{
	init();
}

void setOrthographicProjection(int resX, int resY)
{
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(0,resX,resY,0,-1,1); // invert the y axis, down is positive
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}

void setPerspectiveProjection(double resX, double resY)
{
	extern void glusPerspective( GLdouble fovy, GLdouble aspect, GLdouble near, GLdouble far );
	// 3D
	glMatrixMode(GL_PROJECTION);
	glPushMatrix();
	glLoadIdentity();
	glusPerspective(90.0, resX/resY, 0.1, 1000.0);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}

void teitQuad(float siz)
{
	glBegin (GL_QUADS);
	glTexCoord2f (0.0, 0.0);
	glVertex3f (0.0, 0.0, 0.0);
	glTexCoord2f (1.0, 0.0);
	glVertex3f (siz, 0.0, 0.0);
	glTexCoord2f (1.0, 1.0);
	glVertex3f (siz, siz, 0.0);
	glTexCoord2f (0.0, 1.0);
	glVertex3f (0.0, siz, 0.0);
	glEnd ();
}

float frand()
{
	return (float)rand()/(float)RAND_MAX;
}

void glusPerspective( GLdouble fovy, GLdouble aspect, GLdouble near, GLdouble far )
{
#define TWOPI_OVER_360 0.01745329251994329576923690768489
	GLdouble half_height = near * tan( fovy * 0.5 * TWOPI_OVER_360 );
	GLdouble half_width = half_height * aspect;

	glFrustum( -half_width, half_width, -half_height, half_height, near, far );
} 

void reshapePerspective( int w, int h )
{
	glViewport( 0, 0, (GLsizei)w, (GLsizei)h );
	setPerspectiveProjection(w,h);
}



void Game::init()
{
	extern void setOrthographicProjection(int resX, int resY);
	extern void teitQuad(float siz);
	extern float frand();
	extern void glusPerspective( GLdouble fovy, GLdouble aspect, GLdouble near, GLdouble far );
	extern void setPerspectiveProjection(double resX, double resY);
	extern void GLFWCALL reshapePerspective( int w, int h );

	for(int i=0; i<10; i++)
	{
		Enemy *e = new Enemy();
		e->setPos(frand()*100, frand()*100);
		_gameObjectList.push_back(e);
	}

	std::vector<GameObject> enemies;
	
	camera.posx = 0;
	camera.posy = 0;
	camera.posz = 30;
	camera.vang = 0.0f;
	camera.hang = 0.0f;

	GLMinimal glm(800,600,"GLOW");
	gm = new GraphicsManager();
	player = new Player(gm);
	player->setPos(0,0);
	_gameObjectList.push_back( player );
	setPerspectiveProjection(glm.resX, glm.resY);
	game_scale_x = 40.0f;
	game_scale_y = game_scale_x * glm.resY/glm.resX;

	int oldMouseX, oldMouseY;

	dotTexture = new Texture("dot.png");

	while(glfwGetWindowParam(GLFW_OPENED))
	{
		resX = glm.resX;
		resY = glm.resY;

		time = glm.time;
		update(glm.dt);
		draw(glm.dt);
		
		glm.update();
		oldMouseX = mouseX;
		oldMouseY = mouseY;

		glfwSleep( 1.0 / 1000.0 );
	}

	delete gm;
	delete dotTexture;
}

void Game::cameraUpdate(double dt)
{
	// CAMERA UPDATE
	float mouseSpeedX, mouseSpeedY;
	if(glfwGetMouseButton(GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS)
	{
		float mouseSpd = 0.01f;
		mouseSpeedX = mouseSpd*float(mouseX-oldMouseX);
		mouseSpeedY = mouseSpd*float(mouseY-oldMouseY);
	}
	else
	{
		mouseSpeedX = 0;
		mouseSpeedY = 0;
	}

	float vx = 0.0f;
	float vy = 0.0f;
	float vz = 0.0f;
	if( !glfwGetKey('C') )
	{
		float f = 50.0f;
		//vx = f * float(glfwGetKey('A') - glfwGetKey('D') ) * (float)dt;
		//vy = f * float(glfwGetKey('W') - glfwGetKey('S')) * (float)dt;
		//vz = f * float(glfwGetKey('W') - glfwGetKey('S')) * (float)dt;
	}
	camera.update( -vx,
		vy,
		-vz,
		-mouseSpeedX,
		mouseSpeedY
		);

	float mv[16];
	for(int i=0; i<16; i++)
		mv[i] = (float)camera.getMatrix()[i];

	//glPushMatrix();
	glLoadMatrixd( camera.getMatrix() );
	///////////////////////////////////////  EOF camera
}

void Game::update(double dt)
{
	int mouseX,mouseY;
	glfwGetMousePos(&mouseX, &mouseY);

	cameraUpdate(dt);
}


void Game::draw(double dt)
{
	glClearColor(0,0,0,1);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glfwGetMousePos(&mouseX,&mouseY);

	playFieldMouseX = 2*game_scale_x*(mouseX - resX/2.0f) / resX;
	playFieldMouseY = 2*game_scale_y*-(mouseY - resY/2.0f) / resY;

	playFieldMouseX += camera.posx;
	playFieldMouseY += camera.posy;

	//glDisable(GL_ALPHA_TEST);
	glCullFace(GL_BACK);
	glEnable(GL_BLEND);

	glBlendFunc(GL_SRC_ALPHA,GL_ONE);
	//glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	glEnable(GL_TEXTURE_2D);
	glBindTexture (GL_TEXTURE_2D, dotTexture->_handle );


	glColor3f(1,1,1);
	//
	player->lookAt(playFieldMouseX,playFieldMouseY);
	float thrust_x = float(glfwGetKey('D') - glfwGetKey('A') );
	float thrust_y = float(glfwGetKey('W') - glfwGetKey('S') );
	player->setThrusters(thrust_x, thrust_y);

	for(int i=0; i<_gameObjectList.size(); i++)
	{
		_gameObjectList[i]->draw();
	}

	player->update(dt);

	camera.posx = player->getx();
	camera.posy = player->gety();

	static int seed = 0;
	if ( glfwGetKey(' ') )
	{
		seed++;
	}


	float v1x = -game_scale_x; float v1y = -game_scale_y;
	float v2x = game_scale_x; float v2y = -game_scale_y;
	float v3x = game_scale_x; float v3y = game_scale_y;
	float v4x = -game_scale_x; float v4y = game_scale_y;

	float w = 2.0f;
	glColor4f(1,1,1,1);
	gm->DrawLine(v1x,v1y,v2x,v2y,w);
	gm->DrawLine(v2x,v2y,v3x,v3y,w);
	gm->DrawLine(v3x,v3y,v4x,v4y,w);
	gm->DrawLine(v4x,v4y,v1x,v1y,w);



	float x = playFieldMouseX;
	float y = playFieldMouseY;
	float radi = 2;
	int segs = 3;

	glColor3f(0,0,1);
	for(int j=0; j<segs; j++)
	{
		float ang = (float)j * 2*3.14159f/(segs);
		ang+=time*10;
		float x1 = x + cos(ang)*radi;
		float y1 = y + sin(ang)*radi;


		ang = (float)(j+1) * 2*3.14159f/(segs);
		ang+=time*10;
		float x2 = x + cos(ang)*radi;
		float y2 = y + sin(ang)*radi;

		gm->DrawLine(x1,y1,x2,y2,2.0f);
	}

	const int num_bullets = 150;
	static float bullet_x[num_bullets];
	static float bullet_y[num_bullets];
	static float bullet_life[num_bullets];
	static float bullet_dx[num_bullets];
	static float bullet_dy[num_bullets];

	if(time <= 0.0f)
	{		

		for(int i=0; i<num_bullets; i++)
		{
			bullet_life[i] = 0.0;
		}
	}

	glColor3f(1,0,0);
	float spd = 80;
	for(int i=0; i<num_bullets; i++)
	{
		if( bullet_life[i] > 0.0f ){
			bullet_life[i] -= dt;
			bullet_x[i] += bullet_dx[i] * spd*dt;
			bullet_y[i] += bullet_dy[i] * spd*dt;
			float dx = bullet_dx[i];
			float dy = bullet_dy[i];
			gm->DrawLine(bullet_x[i],bullet_y[i],bullet_x[i]+dx/2,bullet_y[i]+dy/2,10.0f);
		}
	}

	static float bullet_cooldown;

	bullet_cooldown -= dt;

	if(bullet_cooldown <= 0.0 && glfwGetMouseButton(GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS)
	{
		for(int i=0; i<num_bullets; i++)
		{
			if( bullet_life[i] <= 0.0f ){
				bullet_cooldown = 0.125f;

				bullet_x[i] = player->getx();
				bullet_y[i] = player->gety();
				bullet_dx[i] = playFieldMouseX - bullet_x[i];
				bullet_dy[i] = playFieldMouseY - bullet_y[i];
				float mag = sqrt(bullet_dx[i]*bullet_dx[i] + bullet_dy[i]*bullet_dy[i]);
				bullet_dx[i] /= mag;
				bullet_dy[i] /= mag;
				bullet_life[i] = 10;
				break;
			}
		}
	}

	srand(0);
	glColor3f(1,1,1);


	float starWidth = 400;
	for(int i=0; i<500; i++)
	{
		float x = -starWidth+2*starWidth*frand();
		float y = -starWidth+2*starWidth*frand();
		gm->DrawLine(x,y,x+.01f,y+.01f,1.0f );
	}

}